(1) Field of the Invention
The present invention relates to a compiling system in which a source program is converted into an intermediate text and machine language is generated using the intermediate text.
In a compiler for translating a source program into machine language, an intermediate text formed of intermediate codes is produced based on the source program so that the structure and states of the program are represented by the intermediate text. The present invention particularly relates to a compiling system in which operations regarding the intermediate text can be efficiently performed and the superior optimization effect can be obtained.
(2) Description of the Related Art
In the recent years, due to the progress of semiconductor technology, various architectures have been proposed. Particularly, architectures regarding the parallel processing of instructions, such as the VLIW and the superscalar, have been emphasized. The modern compiler must be able to efficiently make instructions using new optimization technology in which characteristics of these architectures are useful.
In a compiler, normally, a structural analysis of a source program is performed so that an intermediate text is obtained, and an optimization process with respect to the intermediate text is performed. The machine language is generated based on the results of the optimization process. A conventional compiler can not process intermediate instructions in each of which a plurality of values are defined.
In addition, the state change of a computer hardware is recorded in a status descriptor. For example, a condition code indicating that a result obtained by subtracting a variable B from a variable A is equal to or less than zero is recorded in a status descriptor. Conventionally, in the status descriptor as described above, the last intermediate code which described the state of an element, such as a register, of the computer hardware or an identifier for which a definition or reference was performed last is recorded. Thus, during the process, information recorded in the status descriptor is successively updated so that the last updated information usually remains in the status descriptor.
When functions are read out from a register, information in the register is destroyed. Thus, to determine the live or dead status of a variable, destruction of information in a register must be considered, other than the consideration of the definition and reference of the variable based on the normal intermediate text. Conventionally, a protocol regarding use of the register cannot be explicitly represented in the intermediate text.
The conventional technique regarding the compiler described above has the following disadvantages.
Since a plurality of values can not be defined in one intermediate code, one operation in the source program must be represented by a plurality of intermediate codes.
For example, a calculation of complex numbers must be represented, from an early step of the translation process for the source program, using a real part and an imaginary part into which each complex number is divided.
In the calculation of complex numbers, calculations for the real part and the imaginary part are separately performed, and a condition code obtained as a result of the calculation for the real part and a condition code obtained as a result of the calculation for the imaginary part must be respectively recorded. In the conventional case, since a plurality of values can not be defined by one intermediate code, in the calculation for complex numbers, the real part and the imaginary part must be separately represented by intermediate codes.
In the optimization process, to determine conditions indicating whether or not processes, such as a transferring process, a copying process and a deleting process, may be applied to an intermediate code, not only the intermediate code but also other intermediate codes sharing the same operation with the intermediate code must be checked. In addition, when an operation is actually applied to the intermediate code, it is necessary to apply the same operation to the other intermediate codes.
For example, in the case where one operation is separately represented by a real part and an imaginary part, such as the case of the calculation of complex numbers described above, it can not be determined, based on only a condition of an intermediate code for the real part, whether the instruction may be transferred, copied or deleted, and it is necessary to check an intermediate code for the imaginary part. In addition, in the case where the intermediate code for the real part is processed, it is necessary to process the intermediate code for the imaginary part.
When the live or dead status of variables is checked, it is necessary to consider the possibility that a variable having the same defining point as a variable defined in an intermediate code is defined in another intermediate code. In the case where the real part and the imaginary part of each complex number are separately represented by intermediate codes as described above, for example, even if operation results for the imaginary part among operation results for a complex number will not be used later, it is necessary for all the operation results for the complex number to be alive so that they may be used the real part. That is, to check the live or dead status of variables in an intermediate codes, it is necessary to consider other intermediate codes.
There are protocols on programming, such as a protocol determining registers in which parameters are to be set, for example, in a process for reading functions. When the live or dead status of a variable is checked, it is necessary to consider the above protocol regarding the registers. In the conventional case, since a plurality of values can not be defined by one intermediate code, the above protocol can not explicitly described by the intermediate code.
As has been described above, in the conventional case, there is a case where an operation in the source program must be represented by a plurality of intermediate codes which are separated from each other, so that the structure of the compiler is complex. As a result, the time required to translate the source program is increased.
In the optimization technique, such as a scheduling technique, in which some intermediate codes are transferred among intermediate codes generated from the source program, it is necessary to restore the state of the computer hardware based on the original intermediate codes after the intermediate codes are transferred. In the conventional case, since an intermediate code or a variable the state of which was determined last is stored in the status descriptor, it is difficult to restore the state of the computer hardware based on the original intermediate codes after the intermediate codes are transferred. As a result, the efficiency of the scheduling of the intermediate codes deteriorates.
That is, in the scheduling process in which the arrangement order of intermediate codes directly obtained from the source program is changed so as to be suitable for being processed by the computer, since there is a case where the arrangement of intermediate codes is not changed so as to be intended by a programmer, it is necessary to restore the state of computer hardware based on the original arrangement order of intermediate codes after the arrangement order of intermediate codes is changed. However, in the conventional case, the state of the computer hardware can not be easily restored after the arrangement order of intermediate codes is changed.
In a CPU having an architecture including a plurality of condition codes, a condition code set based on operation results is not determined independently of the control structure (the order of processes). That is, in the conventional case, the condition code can not be used as a variable, so that the condition code must be set when intermediate codes are generated and the condition code will not be changed later. As a result, the possibility of the scheduling is limited.